package middleware

import (
	"admin-nexus-backend/internal/service"
	"admin-nexus-backend/pkg/logger"
	"admin-nexus-backend/pkg/response"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// PermissionMiddleware 权限验证中间件配置
type PermissionMiddleware struct {
	UserService            *service.UserService
	PermissionCacheService *service.PermissionCacheService
	PermissionLogService   *service.PermissionLogService
}

// NewPermissionMiddleware 创建权限验证中间件
func NewPermissionMiddleware(
	userService *service.UserService,
	permissionCacheService *service.PermissionCacheService,
	permissionLogService *service.PermissionLogService,
) *PermissionMiddleware {
	return &PermissionMiddleware{
		UserService:            userService,
		PermissionCacheService: permissionCacheService,
		PermissionLogService:   permissionLogService,
	}
}

// Permission 权限验证中间件
// 验证用户是否拥有指定的权限码
func (m *PermissionMiddleware) Permission(permissionCode string) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取用户 ID
		userID := GetUserID(c)
		if userID == 0 {
			response.Unauthorized(c, "未登录")
			c.Abort()
			return
		}

		// 获取用户名（用于日志）
		username, _ := c.Get("username")
		usernameStr := ""
		if username != nil {
			usernameStr = username.(string)
		}

		// 从缓存或数据库获取用户权限列表
		userPermissions, err := m.getUserPermissionsWithCache(userID)
		if err != nil {
			logger.Error("获取用户权限失败", zap.Error(err), zap.Uint("userID", userID))

			// 记录拒绝日志
			m.logPermissionDeny(c, userID, usernameStr, permissionCode, "获取用户权限失败")

			response.InternalServerError(c, "获取用户权限失败")
			c.Abort()
			return
		}

		// 检查用户是否拥有该权限
		if !m.hasPermission(userPermissions, permissionCode) {
			logger.Warn("权限验证失败",
				zap.Uint("userID", userID),
				zap.String("username", usernameStr),
				zap.String("permissionCode", permissionCode),
				zap.String("path", c.Request.URL.Path))

			// 记录拒绝日志
			m.logPermissionDeny(c, userID, usernameStr, permissionCode, "用户无此权限")

			response.Forbidden(c, "无权限访问")
			c.Abort()
			return
		}

		// 记录权限访问日志（异步）
		m.logPermissionAccess(c, userID, usernameStr, permissionCode)

		c.Next()
	}
}

// RequireAnyPermission 要求任意一个权限（OR 逻辑）
func (m *PermissionMiddleware) RequireAnyPermission(permissionCodes ...string) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID := GetUserID(c)
		if userID == 0 {
			response.Unauthorized(c, "未登录")
			c.Abort()
			return
		}

		username, _ := c.Get("username")
		usernameStr := ""
		if username != nil {
			usernameStr = username.(string)
		}

		userPermissions, err := m.getUserPermissionsWithCache(userID)
		if err != nil {
			logger.Error("获取用户权限失败", zap.Error(err), zap.Uint("userID", userID))
			m.logPermissionDeny(c, userID, usernameStr, "", "获取用户权限失败")
			response.InternalServerError(c, "获取用户权限失败")
			c.Abort()
			return
		}

		// 检查是否有任意一个权限
		for _, code := range permissionCodes {
			if m.hasPermission(userPermissions, code) {
				m.logPermissionAccess(c, userID, usernameStr, code)
				c.Next()
				return
			}
		}

		logger.Warn("权限验证失败(ANY)",
			zap.Uint("userID", userID),
			zap.String("username", usernameStr),
			zap.Strings("permissionCodes", permissionCodes))

		m.logPermissionDeny(c, userID, usernameStr, "", "用户无任何所需权限")
		response.Forbidden(c, "无权限访问")
		c.Abort()
	}
}

// RequireAllPermissions 要求所有权限（AND 逻辑）
func (m *PermissionMiddleware) RequireAllPermissions(permissionCodes ...string) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID := GetUserID(c)
		if userID == 0 {
			response.Unauthorized(c, "未登录")
			c.Abort()
			return
		}

		username, _ := c.Get("username")
		usernameStr := ""
		if username != nil {
			usernameStr = username.(string)
		}

		userPermissions, err := m.getUserPermissionsWithCache(userID)
		if err != nil {
			logger.Error("获取用户权限失败", zap.Error(err), zap.Uint("userID", userID))
			m.logPermissionDeny(c, userID, usernameStr, "", "获取用户权限失败")
			response.InternalServerError(c, "获取用户权限失败")
			c.Abort()
			return
		}

		// 检查是否拥有所有权限
		for _, code := range permissionCodes {
			if !m.hasPermission(userPermissions, code) {
				logger.Warn("权限验证失败(ALL)",
					zap.Uint("userID", userID),
					zap.String("username", usernameStr),
					zap.String("missingPermission", code))

				m.logPermissionDeny(c, userID, usernameStr, code, "缺少必需权限")
				response.Forbidden(c, "无权限访问")
				c.Abort()
				return
			}
		}

		m.logPermissionAccess(c, userID, usernameStr, permissionCodes[0])
		c.Next()
	}
}

// AdminOnly 仅管理员可访问
func (m *PermissionMiddleware) AdminOnly() gin.HandlerFunc {
	return func(c *gin.Context) {
		userID := GetUserID(c)
		if userID == 0 {
			response.Unauthorized(c, "未登录")
			c.Abort()
			return
		}

		username, _ := c.Get("username")
		usernameStr := ""
		if username != nil {
			usernameStr = username.(string)
		}

		// 获取用户信息检查角色
		user, err := m.UserService.GetUserByID(userID)
		if err != nil {
			logger.Error("获取用户信息失败", zap.Error(err), zap.Uint("userID", userID))
			m.logPermissionDeny(c, userID, usernameStr, "admin_only", "获取用户信息失败")
			response.InternalServerError(c, "获取用户信息失败")
			c.Abort()
			return
		}

		// 检查是否为管理员角色
		isAdmin := false
		for _, role := range user.Roles {
			if role.Code == "admin" || role.Code == "super_admin" {
				isAdmin = true
				break
			}
		}

		if !isAdmin {
			logger.Warn("非管理员访问",
				zap.Uint("userID", userID),
				zap.String("username", usernameStr))

			m.logPermissionDeny(c, userID, usernameStr, "admin_only", "需要管理员权限")
			response.Forbidden(c, "需要管理员权限")
			c.Abort()
			return
		}

		m.logPermissionAccess(c, userID, usernameStr, "admin_only")
		c.Next()
	}
}

// ==================== 辅助方法 ====================

// getUserPermissionsWithCache 从缓存或数据库获取用户权限
func (m *PermissionMiddleware) getUserPermissionsWithCache(userID uint) ([]string, error) {
	// 尝试从缓存获取
	if m.PermissionCacheService != nil && m.PermissionCacheService.IsRedisAvailable() {
		permissions, err := m.PermissionCacheService.GetUserPermissions(userID)
		if err == nil && permissions != nil {
			logger.Debug("从缓存获取用户权限", zap.Uint("userID", userID), zap.Int("count", len(permissions)))
			return permissions, nil
		}
	}

	// 从数据库获取
	permissions, err := m.UserService.GetUserPermissions(userID)
	if err != nil {
		return nil, err
	}

	// 写入缓存
	if m.PermissionCacheService != nil && m.PermissionCacheService.IsRedisAvailable() {
		if err := m.PermissionCacheService.SetUserPermissions(userID, permissions); err != nil {
			logger.Warn("写入权限缓存失败", zap.Error(err), zap.Uint("userID", userID))
		}
	}

	return permissions, nil
}

// hasPermission 检查是否拥有权限
func (m *PermissionMiddleware) hasPermission(userPermissions []string, permissionCode string) bool {
	// 如果权限码为空，表示不需要权限验证
	if permissionCode == "" {
		return true
	}

	for _, perm := range userPermissions {
		if perm == permissionCode {
			return true
		}
		// 支持通配符权限，例如 "system:*" 可以访问所有 "system:" 开头的权限
		if len(perm) > 0 && perm[len(perm)-1] == '*' {
			prefix := perm[:len(perm)-1]
			if len(permissionCode) >= len(prefix) && permissionCode[:len(prefix)] == prefix {
				return true
			}
		}
	}
	return false
}

// logPermissionAccess 记录权限访问日志
func (m *PermissionMiddleware) logPermissionAccess(c *gin.Context, userID uint, username, permissionCode string) {
	if m.PermissionLogService == nil {
		return
	}

	m.PermissionLogService.LogPermissionAccess(service.PermissionLogParams{
		UserID:         userID,
		Username:       username,
		ActionType:     "ACCESS",
		PermissionCode: permissionCode,
		Method:         c.Request.Method,
		Path:           c.Request.URL.Path,
		IP:             c.ClientIP(),
		UserAgent:      c.Request.UserAgent(),
		Result:         1, // 通过
	})
}

// logPermissionDeny 记录权限拒绝日志
func (m *PermissionMiddleware) logPermissionDeny(c *gin.Context, userID uint, username, permissionCode, reason string) {
	if m.PermissionLogService == nil {
		return
	}

	m.PermissionLogService.LogPermissionDeny(service.PermissionLogParams{
		UserID:         userID,
		Username:       username,
		PermissionCode: permissionCode,
		Method:         c.Request.Method,
		Path:           c.Request.URL.Path,
		IP:             c.ClientIP(),
		UserAgent:      c.Request.UserAgent(),
		Result:         0, // 拒绝
		Reason:         reason,
	})
}
